//
// Created by Eric on 2023/1/24.
// 这个类用于生成事件
//

#ifndef UUU_EVENTGENERATOR_H
#define UUU_EVENTGENERATOR_H
#include "Event.h"
#include "Counter.h"
#include "uuu_utility.h"
#include <algorithm>
#include <vector>
#include "CivilizationSet.h"
#include "AsObjectSet.h"
#include "RelationMatrix.h"

class EventGenerator {
private:
    // data
    DatabaseInfo *p_dbi_;
    int* conflict_array_;

public:
    // 构造方法
    void Initialize(DatabaseInfo* p_dbi);
    EventGenerator(){p_dbi_ = nullptr;}

    // 遍历所有文明并且生成事件
    auto SelectEvent();
    // 完善事件的各种细节
    auto SelectTarget(vector<Event>& events);
};

void EventGenerator::Initialize(DatabaseInfo *p_dbi) {
    p_dbi_ = p_dbi;
}

auto EventGenerator::SelectTarget(vector<Event> &events) {
    // 下面代码是为解决战争冲突 = = = = = = =

    // 用于存储被选为同一目标的天体，仅适用于战争事件
    struct info{
        int related_event_number; // 以该索引为源的事件数量
        Event* valid_event; // 最终有效的事件指针
        double valid_event_poy; // 最终有效事件的优先级
        info(){
            related_event_number = 0;
            valid_event_poy = -1;
            valid_event = nullptr;
        }
    };

    vector<info> conflict_map;
    conflict_map.resize(p_dbi_->num_of_asobject);
    // 上面代码是为解决战争冲突 = = = = = = =

    CivilizationSet &civilization_set = *p_dbi_->p_civilization_set;
    RelationMatrix &relation_matrix = *p_dbi_->p_relation_matrix;
    AsObjectSet &asobject_set = *p_dbi_->p_asobject_set;
    // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!注意break！！！！！！！！！！



    for (auto &event: events) {
        switch (event.type()) {
            // ===================
            // ===================
            case Event::Detect: {
                int source_idx = event.source_cz_idx();

                // 获取可观测e范围
                double ob_range = Counter::ob_range(civilization_set.GetTechnologyLevel(source_idx),
                                                    p_dbi_->universe_size);

                // 确定观测星球
                // 目前逻辑
                // 找到该文明拥有的所有天体中，离目标天体最近的，如果距离小于可观测范围，那么观测
                int target_asobject_idx = -1; // 置-1表示还没有找到
                for (auto &[idx, asobject]: asobject_set) {
                    if (target_asobject_idx != -1) break;

                    if (relation_matrix.GetObState(source_idx, idx) == RelationMatrix::UNKNOWN) {
                        for (auto ao_idx: relation_matrix.GetCivilizationOwnAsObjectIdx(source_idx)) {
                            if (asobject_set.GetDistance(source_idx, ao_idx) < ob_range) {
                                target_asobject_idx = idx;
                                break;
                            }
                        }
                    } else {
                        continue;
                    }
                }

                event.SetTargetCzIdx(target_asobject_idx);
                break;
            }
                // ===================
                // ===================
            case Event::War: {
                int source_idx = event.source_cz_idx();
                 
                vector<int> candidate_ao_idxs = relation_matrix.GetCzStarMap(source_idx);
                sort(candidate_ao_idxs.begin(), candidate_ao_idxs.end(), [&](int a, int b) -> bool {
                    switch (relation_matrix.GetAoOwnerId(a)) {
                        case -1: {
                            return true;
                        }
                        default:
                            switch (relation_matrix.GetAoOwnerId(b)) {
                                case -1:
                                    return false;
                                default:
                                    if (civilization_set.MilitaryLagBehind(a, b)) {
                                        return true;
                                    }
                            }
                    }
                    return false;
                });

                int selected_index = candidate_ao_idxs[0];


                // 如果选定的星球是个蛮荒星球
                if(p_dbi_->p_relation_matrix->GetAoOwnerId(selected_index) == -1)
                    event.AddState(Event::Colonize);

                event.SetTargetCzIdx(selected_index);

                conflict_map[selected_index].related_event_number++;
                // 说明有其他以该星球为源的战争事件
                if(conflict_map[selected_index].related_event_number!=0) {
                    // 先假设该事件无效
                    event.AddState(Event::Jump);

                    int _source_cz_idx = event.source_cz_idx();
                    // 源文明的母星索引
                    int source_cz_mother_aso_idx = civilization_set.GetCivilization(_source_cz_idx).mother_aso_idx();

                    // 距离
                    double distance = asobject_set.GetDistance(source_cz_mother_aso_idx, event.target_cz_idx());

                    // 优先级
                    double cur_poy = 1 / distance * civilization_set.GetCivilization    (_source_cz_idx).technology_level();

                    if(conflict_map[selected_index].valid_event_poy < cur_poy){
                        conflict_map[selected_index].valid_event = &event;
                        conflict_map[selected_index].valid_event_poy = cur_poy;
                    }

                }
                break;
            }
            case Event::Develop:
                break;
            case Event::Null:
                break;
            default:
                break;
        }
    }

    // 处理战争事件 = = = = =
    for(int i = 0; i < p_dbi_->num_of_asobject; i++){
        if(conflict_map[i].related_event_number >= 1){
            conflict_map[i].valid_event->SubState(Event::Jump);
        }
    }

}

auto EventGenerator::SelectEvent() {
    // 目前的事件生成逻辑
    // 如果文明的星图上没有任何文明，那就探测
    // 否则，做一次概率测试，决定是否开战
    // 否则，就发展

    std::vector<Event> product;
    // 这个遍历实际上就是在遍历CivilizationSet内部的unordered_map
    for(auto&[idx, civilization]:*p_dbi_->p_civilization_set){
        if(civilization.asobject_known() == 0){
            product.emplace_back(Event(idx, -1, Event::EventType::Detect, 0));
        }
        else if(Counter::ChanceTest(civilization.warlike())){
            product.emplace_back(Event(idx, -1, Event::EventType::War, 0));
        }
        else{
            product.emplace_back(Event(idx, idx, Event::Develop, 0));
        }
    }

    SelectTarget(product);
    return product;
}

#endif //UUU_EVENTGENERATOR_H
